package com.soen6441.generics;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;

class SpellChecker {
    static final int FIRST_LETTER = 0;
    final int maxEdditDistance;
    Set<String> words = new HashSet<String>();
    SetMultimap<Character, String> startsWith
            = HashMultimap.create();
    SetMultimap<Character, String> endsWith
                = HashMultimap.create();

    public SpellChecker(int maxEdditDistance) {
        this.maxEdditDistance = maxEdditDistance;
    }

    void addWord(String word){
        word = word.toLowerCase();
        words.add(word);
        startsWith.put(word.charAt(FIRST_LETTER), word);
        endsWith.put(word.charAt(lastLetter(word)), word);
    }

    private int lastLetter(String word) {
        return word.length() -1;
    }

    void addWords(String fromFile){
        try {
            List<String> lines = FileUtils.readLines( new File(fromFile));
            for (String line : lines ){
                addWord(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    Iterable<Correction> corrections(String word){
        word = word.toLowerCase();
        Set<Correction> allCorrections
                = new TreeSet<Correction>( new Correction.CorrectionComparator() );
        if ( words.contains(word) )
            return allCorrections; // spelled correctly

        Set<String> wordsWithSameFirstLetter
                = startsWith.get(word.charAt(FIRST_LETTER));

        Set<String> wordsWithSameLastLetter =
                endsWith.get(word.charAt(lastLetter(word)));

        addCorrections(word, wordsWithSameFirstLetter, allCorrections);
        addCorrections(word, wordsWithSameLastLetter, allCorrections);

        return allCorrections;
    }

    private void addCorrections(String word, Set<String> words, Set<Correction> corrections) {
        int edditDistance = 0;
        for(String correction : words) {
            edditDistance = StringUtils.getLevenshteinDistance(word, correction);
            if (edditDistance > maxEdditDistance)
                continue;
            corrections.add(new Correction(correction, edditDistance));
        }
    }
}
